use std::net::SocketAddr;
use std::path::PathBuf;
use std::sync::Arc;

use axum::Router;
use tower_http::trace::TraceLayer;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};

/// OxiCloud - Cloud Storage Platform
///
/// OxiCloud is a NextCloud-like file storage system built in Rust with a focus on 
/// performance, security, and clean architecture. The system provides:
///
/// - File and folder management with rich metadata
/// - User authentication and authorization
/// - File trash system with automatic cleanup
/// - Efficient handling of large files through parallel processing
/// - Compression capabilities for bandwidth optimization
/// - RESTful API and web interface
///
/// The architecture follows the Clean/Hexagonal Architecture pattern with:
///
/// - Domain Layer: Core business entities and repository interfaces (domain/*)
/// - Application Layer: Use cases and service orchestration (application/*)
/// - Infrastructure Layer: Technical implementations of repositories (infrastructure/*)
/// - Interface Layer: API endpoints and web controllers (interfaces/*)
///
/// Dependencies are managed through dependency inversion, with high-level modules
/// defining interfaces (ports) that low-level modules implement (adapters).
///
/// @author OxiCloud Development Team

/// Common utilities, configuration, and error handling
mod common;
/// Core domain model, entities, and business rules
mod domain;
/// Application services, use cases, and DTOs
mod application;
/// Technical implementations of repositories and services
mod infrastructure;
/// External interfaces like API endpoints and web controllers
mod interfaces;

use application::services::folder_service::FolderService;
use application::services::file_service::FileService;
use application::services::i18n_application_service::I18nApplicationService;
use application::services::storage_mediator::FileSystemStorageMediator;
use application::services::share_service::ShareService;
use application::services::favorites_service::FavoritesService;
use domain::services::path_service::PathService;
use infrastructure::repositories::folder_fs_repository::FolderFsRepository;
use infrastructure::repositories::file_fs_repository::FileFsRepository;
use infrastructure::repositories::parallel_file_processor::ParallelFileProcessor;
use infrastructure::repositories::share_fs_repository::ShareFsRepository;
use infrastructure::services::file_system_i18n_service::FileSystemI18nService;
use infrastructure::services::id_mapping_service::IdMappingService;
use infrastructure::services::id_mapping_optimizer::IdMappingOptimizer;
use infrastructure::services::file_metadata_cache::FileMetadataCache;
use infrastructure::services::buffer_pool::BufferPool;
use infrastructure::services::compression_service::GzipCompressionService;
use interfaces::{create_api_routes, web::create_web_routes};
use application::services::trash_service::TrashService;
use infrastructure::repositories::trash_fs_repository::TrashFsRepository;
use infrastructure::services::trash_cleanup_service::TrashCleanupService;
use common::db::create_database_pool;
use common::auth_factory::create_auth_services;
use common::di::AppState;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize tracing
    tracing_subscriber::registry()
        .with(tracing_subscriber::EnvFilter::new(
            std::env::var("RUST_LOG").unwrap_or_else(|_| "info".into()),
        ))
        .with(tracing_subscriber::fmt::layer())
        .init();

    // Load configuration from environment variables
    let config = common::config::AppConfig::from_env();
    
    // Set up storage directory
    let storage_path = config.storage_path.clone();
    if !storage_path.exists() {
        std::fs::create_dir_all(&storage_path).expect("Failed to create storage directory");
    }

    // Set up locales directory
    let locales_path = PathBuf::from("./static/locales");
    if !locales_path.exists() {
        std::fs::create_dir_all(&locales_path).expect("Failed to create locales directory");
    }
    
    // Initialize database if auth is enabled
    let db_pool = if config.features.enable_auth {
        match create_database_pool(&config).await {
            Ok(pool) => {
                tracing::info!("PostgreSQL database pool initialized successfully");
                Some(Arc::new(pool))
            },
            Err(e) => {
                tracing::error!("Failed to initialize database pool: {}", e);
                None
            }
        }
    } else {
        None
    };
    
    // Create a reference to db_pool for use throughout the code
    let db_pool_ref = db_pool.as_ref();

    // Initialize path service
    let path_service = Arc::new(PathService::new(storage_path.clone()));
    
    // Initialize ID mapping service for folders
    let folder_id_mapping_path = storage_path.join("folder_ids.json");
    let folder_id_mapping_service = Arc::new(
        IdMappingService::new(folder_id_mapping_path).await
            .expect("Failed to initialize folder ID mapping service")
    );
    
    // Initialize ID mapping service for files
    let file_id_mapping_path = storage_path.join("file_ids.json");
    let file_id_mapping_service = Arc::new(
        IdMappingService::new(file_id_mapping_path).await
            .expect("Failed to initialize file ID mapping service")
    );
    
    // For backward compatibility, use folder ID service as the base ID mapping service
    let base_id_mapping_service = folder_id_mapping_service.clone();
    
    // Create optimized ID mapping service with batch processing and caching
    let id_mapping_optimizer = Arc::new(
        IdMappingOptimizer::new(base_id_mapping_service.clone())
    );
    
    // Initialize folder repository with all required components
    let folder_repository = Arc::new(FolderFsRepository::new(
        storage_path.clone(),
        Arc::new(FileSystemStorageMediator::new_stub()), // Temporary stub (will be replaced)
        base_id_mapping_service.clone(),
        path_service.clone()
    ));
    
    // Initialize storage mediator
    let storage_mediator = Arc::new(FileSystemStorageMediator::new(
        folder_repository.clone(),
        path_service.clone(),
        id_mapping_optimizer.clone()
    ));
    
    // Update folder repository with proper storage mediator
    // This replaces the stub we initialized it with
    let folder_repository = Arc::new(FolderFsRepository::new(
        storage_path.clone(),
        storage_mediator.clone(),
        base_id_mapping_service.clone(),
        path_service.clone()
    ));
    
    // Start cleanup task for ID mapping optimizer
    IdMappingOptimizer::start_cleanup_task(id_mapping_optimizer.clone());
    
    tracing::info!("ID mapping optimizer initialized with batch processing and caching");
    
    // Initialize the metadata cache 
    let config = common::config::AppConfig::default();
    let metadata_cache = Arc::new(FileMetadataCache::default_with_config(config.clone()));
    
    // Start the periodic cleanup task for cache maintenance
    let cache_clone = metadata_cache.clone();
    tokio::spawn(async move {
        FileMetadataCache::start_cleanup_task(cache_clone).await;
    });
    
    // Initialize the buffer pool for memory optimization
    // Use larger buffer size for better performance with large files
    let buffer_pool = BufferPool::new(256 * 1024, 50, 120); // 256KB buffers, 50 max, 2 min TTL
    
    // Start the buffer pool cleanup task
    BufferPool::start_cleaner(buffer_pool.clone());
    
    tracing::info!("Buffer pool initialized with 50 buffers of 256KB each");
    
    // Initialize parallel file processor with buffer pool
    let parallel_processor = Arc::new(ParallelFileProcessor::new_with_buffer_pool(
        config.clone(),
        buffer_pool.clone()
    ));
    
    // Initialize compression service with buffer pool
    let _compression_service = Arc::new(GzipCompressionService::new_with_buffer_pool(
        buffer_pool.clone()
    ));
    
    // Initialize file repository with mediator, ID mapping service, metadata cache, and parallel processor
    let file_repository = Arc::new(FileFsRepository::new_with_processor(
        storage_path.clone(), 
        storage_mediator,
        file_id_mapping_service.clone(), // Use the file-specific ID mapping service
        path_service.clone(),
        metadata_cache.clone(), // Clone to keep a reference for later use
        parallel_processor
    ));

    // Initialize application services
    let folder_service = Arc::new(FolderService::new(folder_repository.clone()));
    let file_service = Arc::new(FileService::new(file_repository.clone()));
    
    // Initialize trash service if enabled
    let trash_repository = if config.features.enable_trash {
        Some(Arc::new(TrashFsRepository::new(
            storage_path.as_path(),
            base_id_mapping_service.clone(),
        )))
    } else {
        None
    };
    
    // Create adapters for repositories (using domain interfaces instead of ports)
    struct DomainFileRepoAdapter {
        repo: Arc<dyn application::ports::outbound::FileStoragePort>
    }
    
    impl DomainFileRepoAdapter {
        fn new(repo: Arc<dyn application::ports::outbound::FileStoragePort>) -> Self {
            Self { repo }
        }
    }
    
    #[async_trait::async_trait]
    impl domain::repositories::file_repository::FileRepository for DomainFileRepoAdapter {
        async fn save_file_from_bytes(
            &self,
            name: String,
            folder_id: Option<String>,
            content_type: String,
            content: Vec<u8>,
        ) -> domain::repositories::file_repository::FileRepositoryResult<domain::entities::file::File> {
            self.repo.save_file(name, folder_id, content_type, content)
                .await
                .map_err(|e| domain::repositories::file_repository::FileRepositoryError::Other(format!("{}", e)))
        }
        
        async fn save_file_with_id(
            &self,
            id: String,
            name: String,
            folder_id: Option<String>,
            content_type: String,
            content: Vec<u8>,
        ) -> domain::repositories::file_repository::FileRepositoryResult<domain::entities::file::File> {
            Err(domain::repositories::file_repository::FileRepositoryError::Other("Not implemented".to_string()))
        }
        
        async fn get_file_by_id(&self, id: &str) -> domain::repositories::file_repository::FileRepositoryResult<domain::entities::file::File> {
            self.repo.get_file(id)
                .await
                .map_err(|e| domain::repositories::file_repository::FileRepositoryError::Other(format!("{}", e)))
        }
        
        async fn list_files(&self, folder_id: Option<&str>) -> domain::repositories::file_repository::FileRepositoryResult<Vec<domain::entities::file::File>> {
            self.repo.list_files(folder_id)
                .await
                .map_err(|e| domain::repositories::file_repository::FileRepositoryError::Other(format!("{}", e)))
        }
        
        async fn delete_file(&self, id: &str) -> domain::repositories::file_repository::FileRepositoryResult<()> {
            self.repo.delete_file(id)
                .await
                .map_err(|e| domain::repositories::file_repository::FileRepositoryError::Other(format!("{}", e)))
        }
        
        async fn delete_file_entry(&self, id: &str) -> domain::repositories::file_repository::FileRepositoryResult<()> {
            self.delete_file(id).await
        }
        
        async fn get_file_content(&self, id: &str) -> domain::repositories::file_repository::FileRepositoryResult<Vec<u8>> {
            self.repo.get_file_content(id)
                .await
                .map_err(|e| domain::repositories::file_repository::FileRepositoryError::Other(format!("{}", e)))
        }
        
        async fn get_file_stream(&self, id: &str) -> domain::repositories::file_repository::FileRepositoryResult<Box<dyn futures::Stream<Item = Result<bytes::Bytes, std::io::Error>> + Send>> {
            self.repo.get_file_stream(id)
                .await
                .map_err(|e| domain::repositories::file_repository::FileRepositoryError::Other(format!("{}", e)))
        }
        
        async fn move_file(&self, id: &str, target_folder_id: Option<String>) -> domain::repositories::file_repository::FileRepositoryResult<domain::entities::file::File> {
            self.repo.move_file(id, target_folder_id)
                .await
                .map_err(|e| domain::repositories::file_repository::FileRepositoryError::Other(format!("{}", e)))
        }
        
        async fn get_file_path(&self, id: &str) -> domain::repositories::file_repository::FileRepositoryResult<domain::services::path_service::StoragePath> {
            self.repo.get_file_path(id)
                .await
                .map_err(|e| domain::repositories::file_repository::FileRepositoryError::Other(format!("{}", e)))
        }
        
        async fn move_to_trash(&self, file_id: &str) -> domain::repositories::file_repository::FileRepositoryResult<()> {
            // Since we're using TrashService to handle trashing, this method is not directly used
            // but we'll implement it by delegating to the repository's delete_file method
            self.repo.delete_file(file_id)
                .await
                .map_err(|e| domain::repositories::file_repository::FileRepositoryError::Other(format!("{}", e)))
        }
        
        async fn restore_from_trash(&self, file_id: &str, original_path: &str) -> domain::repositories::file_repository::FileRepositoryResult<()> {
            
            
            tracing::info!("Restoring file from trash: {} to {}", file_id, original_path);
            
            // We need to get the file from trash first to ensure it exists
            match self.repo.get_file(file_id).await {
                Ok(_) => {
                    // Extract the parent folder ID from the original path if available
                    let path_components: Vec<&str> = original_path.split('/').collect();
                    let parent_folder: Option<String> = if path_components.len() > 1 {
                        // Try to extract folder ID from path, but this is just a simplified approach
                        // In a real implementation, we would need to find or create the folder
                        tracing::info!("Attempting to restore to parent folder from path: {}", original_path);
                        None // No folder ID for now, will go to root
                    } else {
                        None // No parent folder, go to root
                    };
                    
                    // Use move_file to attempt to restore the file to its original location or root
                    match self.repo.move_file(file_id, parent_folder).await {
                        Ok(_) => {
                            tracing::info!("Successfully restored file from trash: {}", file_id);
                            Ok(())
                        },
                        Err(e) => {
                            tracing::error!("Failed to restore file from trash: {}", e);
                            Err(domain::repositories::file_repository::FileRepositoryError::Other(format!("Failed to restore file: {}", e)))
                        }
                    }
                },
                Err(e) => {
                    tracing::error!("File not found in trash: {}", e);
                    Err(domain::repositories::file_repository::FileRepositoryError::NotFound(file_id.to_string()))
                }
            }
        }
        
        async fn delete_file_permanently(&self, file_id: &str) -> domain::repositories::file_repository::FileRepositoryResult<()> {
            tracing::info!("Permanently deleting file: {}", file_id);
            
            // Directly attempt to delete the file using the file service
            match self.repo.delete_file(file_id).await {
                Ok(_) => {
                    tracing::info!("Successfully deleted file permanently: {}", file_id);
                    Ok(())
                },
                Err(e) => {
                    tracing::error!("Failed to permanently delete file: {}", e);
                    Err(domain::repositories::file_repository::FileRepositoryError::Other(format!("Failed to delete file permanently: {}", e)))
                }
            }
        }
        
        async fn update_file_content(&self, file_id: &str, content: Vec<u8>) -> domain::repositories::file_repository::FileRepositoryResult<()> {
            tracing::info!("Updating content for file: {}", file_id);
            
            self.repo.update_file_content(file_id, content)
                .await
                .map_err(|e| {
                    tracing::error!("Failed to update file content: {}", e);
                    domain::repositories::file_repository::FileRepositoryError::Other(format!("Failed to update file content: {}", e))
                })
        }
    }
    
    struct DomainFolderRepoAdapter {
        repo: Arc<dyn application::ports::outbound::FolderStoragePort>
    }
    
    impl DomainFolderRepoAdapter {
        fn new(repo: Arc<dyn application::ports::outbound::FolderStoragePort>) -> Self {
            Self { repo }
        }
    }
    
    #[async_trait::async_trait]
    impl domain::repositories::folder_repository::FolderRepository for DomainFolderRepoAdapter {
        async fn create_folder(&self, name: String, parent_id: Option<String>) -> domain::repositories::folder_repository::FolderRepositoryResult<domain::entities::folder::Folder> {
            self.repo.create_folder(name, parent_id)
                .await
                .map_err(|e| domain::repositories::folder_repository::FolderRepositoryError::Other(format!("{}", e)))
        }
        
        async fn get_folder_by_id(&self, id: &str) -> domain::repositories::folder_repository::FolderRepositoryResult<domain::entities::folder::Folder> {
            self.repo.get_folder(id)
                .await
                .map_err(|e| domain::repositories::folder_repository::FolderRepositoryError::Other(format!("{}", e)))
        }
        
        async fn get_folder_by_storage_path(&self, storage_path: &domain::services::path_service::StoragePath) -> domain::repositories::folder_repository::FolderRepositoryResult<domain::entities::folder::Folder> {
            self.repo.get_folder_by_path(storage_path)
                .await
                .map_err(|e| domain::repositories::folder_repository::FolderRepositoryError::Other(format!("{}", e)))
        }
        
        async fn list_folders(&self, parent_id: Option<&str>) -> domain::repositories::folder_repository::FolderRepositoryResult<Vec<domain::entities::folder::Folder>> {
            self.repo.list_folders(parent_id)
                .await
                .map_err(|e| domain::repositories::folder_repository::FolderRepositoryError::Other(format!("{}", e)))
        }
        
        async fn list_folders_paginated(
            &self, 
            parent_id: Option<&str>, 
            offset: usize, 
            limit: usize,
            include_total: bool
        ) -> domain::repositories::folder_repository::FolderRepositoryResult<(Vec<domain::entities::folder::Folder>, Option<usize>)> {
            self.repo.list_folders_paginated(parent_id, offset, limit, include_total)
                .await
                .map_err(|e| domain::repositories::folder_repository::FolderRepositoryError::Other(format!("{}", e)))
        }
        
        async fn rename_folder(&self, id: &str, new_name: String) -> domain::repositories::folder_repository::FolderRepositoryResult<domain::entities::folder::Folder> {
            self.repo.rename_folder(id, new_name)
                .await
                .map_err(|e| domain::repositories::folder_repository::FolderRepositoryError::Other(format!("{}", e)))
        }
        
        async fn move_folder(&self, id: &str, new_parent_id: Option<&str>) -> domain::repositories::folder_repository::FolderRepositoryResult<domain::entities::folder::Folder> {
            self.repo.move_folder(id, new_parent_id)
                .await
                .map_err(|e| domain::repositories::folder_repository::FolderRepositoryError::Other(format!("{}", e)))
        }
        
        async fn delete_folder(&self, id: &str) -> domain::repositories::folder_repository::FolderRepositoryResult<()> {
            self.repo.delete_folder(id)
                .await
                .map_err(|e| domain::repositories::folder_repository::FolderRepositoryError::Other(format!("{}", e)))
        }
        
        async fn folder_exists_at_storage_path(&self, storage_path: &domain::services::path_service::StoragePath) -> domain::repositories::folder_repository::FolderRepositoryResult<bool> {
            self.repo.folder_exists(storage_path)
                .await
                .map_err(|e| domain::repositories::folder_repository::FolderRepositoryError::Other(format!("{}", e)))
        }
        
        async fn get_folder_storage_path(&self, id: &str) -> domain::repositories::folder_repository::FolderRepositoryResult<domain::services::path_service::StoragePath> {
            self.repo.get_folder_path(id)
                .await
                .map_err(|e| domain::repositories::folder_repository::FolderRepositoryError::Other(format!("{}", e)))
        }
        
        async fn folder_exists(&self, path: &std::path::PathBuf) -> domain::repositories::folder_repository::FolderRepositoryResult<bool> {
            Err(domain::repositories::folder_repository::FolderRepositoryError::Other("Not implemented".to_string()))
        }
        
        async fn get_folder_by_path(&self, path: &std::path::PathBuf) -> domain::repositories::folder_repository::FolderRepositoryResult<domain::entities::folder::Folder> {
            Err(domain::repositories::folder_repository::FolderRepositoryError::Other("Not implemented".to_string()))
        }
        
        async fn move_to_trash(&self, folder_id: &str) -> domain::repositories::folder_repository::FolderRepositoryResult<()> {
            // Since we're using TrashService to handle trashing, this method is not directly used
            // but we'll still use delete_folder since the underlying repository has proper trash support
            self.repo.delete_folder(folder_id)
                .await
                .map_err(|e| domain::repositories::folder_repository::FolderRepositoryError::Other(format!("{}", e)))
        }
        
        async fn restore_from_trash(&self, folder_id: &str, original_path: &str) -> domain::repositories::folder_repository::FolderRepositoryResult<()> {
            // Convert the original_path to a StoragePath for the repository
            use crate::domain::services::path_service::StoragePath;
            let storage_path = StoragePath::from_string(original_path);
            let _ = storage_path; // Prevent unused variable warning
            
            // The underlying repo doesn't have a direct API for this, but the implementation exists
            // in the folder repository through TrashService
            // This should be coordinated through TrashService instead
            Err(domain::repositories::folder_repository::FolderRepositoryError::Other(
                "Restore from trash should be handled by TrashService, not through this adapter".to_string()))
        }
        
        async fn delete_folder_permanently(&self, folder_id: &str) -> domain::repositories::folder_repository::FolderRepositoryResult<()> {
            // The repository now has proper implementation for permanent deletion
            // But we still use delete_folder since that's the method available on FolderStoragePort
            self.delete_folder(folder_id).await
        }
    }
    
    // Create repository adapters
    let file_repo_adapter = Arc::new(DomainFileRepoAdapter::new(file_repository.clone()));
    let folder_repo_adapter = Arc::new(DomainFolderRepoAdapter::new(folder_repository.clone()));
    
    // Create the trash service with properly typed adapters
    let trash_service = if let Some(ref trash_repo) = trash_repository {
        let service = Arc::new(TrashService::new(
            trash_repo.clone(),
            file_repo_adapter,
            folder_repo_adapter,
            config.storage.trash_retention_days,
        ));
        
        // Initialize trash cleanup service
        let cleanup_service = TrashCleanupService::new(
            service.clone(),
            trash_repo.clone(),
            24, // Run cleanup every 24 hours
        );
        
        // Start cleanup job if trash is enabled
        if config.features.enable_trash {
            cleanup_service.start_cleanup_job().await;
            tracing::info!("Trash cleanup service started with daily schedule");
        }
        
        Some(service as Arc<dyn application::ports::trash_ports::TrashUseCase>)
    } else {
        None
    };
    
    // Initialize i18n service
    let i18n_repository = Arc::new(FileSystemI18nService::new(locales_path.clone()));
    let i18n_service = Arc::new(I18nApplicationService::new(i18n_repository.clone()));
    
    // Preload translations
    if let Err(e) = i18n_service.load_translations(domain::services::i18n_service::Locale::English).await {
        tracing::warn!("Failed to load English translations: {}", e);
    }
    if let Err(e) = i18n_service.load_translations(domain::services::i18n_service::Locale::Spanish).await {
        tracing::warn!("Failed to load Spanish translations: {}", e);
    }
    
    tracing::info!("Compression service initialized with buffer pool support");
    
    // Initialize auth services if enabled and database connection is available
    let auth_services = if config.features.enable_auth && db_pool_ref.is_some() {
        match create_auth_services(
            &config, 
            db_pool_ref.unwrap().clone(),
            Some(folder_service.clone())  // Pasar el servicio de carpetas para creación automática de carpetas de usuario
        ).await {
            Ok(services) => {
                tracing::info!("Authentication services initialized successfully with folder service");
                Some(services)
            },
            Err(e) => {
                tracing::error!("Failed to initialize authentication services: {}", e);
                None
            }
        }
    } else {
        None
    };
    
    // Create AppState for DI container
    let core_services = common::di::CoreServices {
        path_service: path_service.clone(),
        cache_manager: Arc::new(infrastructure::services::cache_manager::StorageCacheManager::default()),
        id_mapping_service: base_id_mapping_service.clone(), // We keep using the folder ID mapping service for core services
        config: config.clone(),
    };
    
    // Crear stubs para los repositorios
    let file_read_stub = Arc::new(infrastructure::repositories::FileFsReadRepository::default_stub());
    let file_write_stub = Arc::new(infrastructure::repositories::FileFsWriteRepository::default_stub());
    let storage_mediator_stub = Arc::new(application::services::storage_mediator::FileSystemStorageMediator::new_stub());
    let metadata_manager = Arc::new(infrastructure::repositories::FileMetadataManager::default());
    let path_resolver_stub = Arc::new(infrastructure::repositories::FilePathResolver::default_stub());
    
    let repository_services = common::di::RepositoryServices {
        folder_repository: Arc::new(FolderFsRepository::new(
            storage_path.clone(),
            storage_mediator_stub.clone(),
            folder_id_mapping_service.clone(),
            path_service.clone()
        )),
        file_repository: Arc::new(FileFsRepository::new(
            storage_path.clone(), 
            storage_mediator_stub.clone(),
            file_id_mapping_service.clone(),
            path_service.clone(),
            metadata_cache.clone(),
        )),
        file_read_repository: file_read_stub,
        file_write_repository: file_write_stub,
        i18n_repository: i18n_repository.clone(),
        storage_mediator: storage_mediator_stub,
        metadata_manager,
        path_resolver: path_resolver_stub,
        trash_repository: trash_repository.clone().map(|repo| {
            // Convert Arc<TrashFsRepository> to Arc<dyn TrashRepository>
            let repo: Arc<dyn crate::domain::repositories::trash_repository::TrashRepository> = repo;
            repo
        }),
    };
    
    // Create the search service
    let search_service: Option<Arc<dyn application::ports::inbound::SearchUseCase>> = {
        // Create the search service with caching
        let search_service = Arc::new(application::services::search_service::SearchService::new(
            file_repository.clone(),
            folder_repository.clone(),
            300, // Cache TTL in seconds (5 minutes)
            1000, // Maximum cache entries
        ));
        
        tracing::info!("Search service initialized with caching (TTL: 300s, max entries: 1000)");
        Some(search_service)
    };
    
    // Initialize share repository and service if enabled
    let share_service: Option<Arc<dyn application::ports::share_ports::ShareUseCase>> = if config.features.enable_file_sharing {
        let share_repository = Arc::new(ShareFsRepository::new(
            Arc::new(config.clone())
        ));
        
        let share_service = Arc::new(ShareService::new(
            Arc::new(config.clone()),
            share_repository,
            file_repository.clone(),
            folder_repository.clone()
        ));
        
        tracing::info!("File sharing service initialized successfully");
        Some(share_service)
    } else {
        tracing::info!("File sharing service is disabled in configuration");
        None
    };

    // Initialize favorites service if database is available
    let favorites_service: Option<Arc<dyn application::ports::favorites_ports::FavoritesUseCase>> = 
    if let Some(pool) = db_pool_ref {
        // Create a new favorites service with the database pool
        let favorites_service = Arc::new(FavoritesService::new(
            pool.clone()
        ));
        
        tracing::info!("Favorites service initialized successfully");
        Some(favorites_service)
    } else {
        tracing::info!("Favorites service is disabled (requires database connection)");
        None
    };
    
    // Initialize recent items service if database is available
    let recent_service: Option<Arc<dyn application::ports::recent_ports::RecentItemsUseCase>> = 
    if let Some(pool) = db_pool_ref {
        // Create a new service with the database pool
        let service = Arc::new(application::services::recent_service::RecentService::new(
            pool.clone(),
            50 // Maximum recent items per user
        ));
        
        tracing::info!("Recent items service initialized successfully");
        Some(service)
    } else {
        tracing::info!("Recent items service is disabled (requires database connection)");
        None
    };
    
    // For now, we'll use a placeholder for the contact service
    // Instead of using the real PostgreSQL repositories, we'll create a dummy implementation
    // This makes the code compile, and we can replace it with the real implementation later
    let contact_service: Option<Arc<dyn application::ports::storage_ports::StorageUseCase>> = None;

    let application_services = common::di::ApplicationServices {
        folder_service: folder_service.clone(),
        file_service: file_service.clone(),
        file_upload_service: Arc::new(application::services::file_upload_service::FileUploadService::default_stub()),
        file_retrieval_service: Arc::new(application::services::file_retrieval_service::FileRetrievalService::default_stub()),
        file_management_service: Arc::new(application::services::file_management_service::FileManagementService::default_stub()),
        file_use_case_factory: Arc::new(application::services::file_use_case_factory::AppFileUseCaseFactory::default_stub()),
        i18n_service: i18n_service.clone(),
        trash_service: trash_service.clone(),
        search_service: search_service.clone(),
        share_service: share_service.clone(),
        favorites_service: favorites_service.clone(),
        recent_service: recent_service.clone()
    };
    
    // Create the AppState without Arc first
    let calendar_service_option = None;
    
    let mut app_state = AppState {
        core: core_services,
        repositories: repository_services,
        applications: application_services,
        db_pool: db_pool.clone(),
        auth_service: auth_services.clone(),
        trash_service: trash_service.clone(),
        share_service: share_service.clone(),
        favorites_service: favorites_service.clone(),
        recent_service: recent_service.clone(),
        storage_usage_service: None,
        calendar_service: calendar_service_option,
        contact_service: contact_service.clone(),
    };
    
    // Initialize storage usage service
    let _storage_usage_service = if let Some(pool) = db_pool_ref {
        // Create a user repository that implements UserStoragePort
        let user_repository = Arc::new(
            infrastructure::repositories::pg::UserPgRepository::new(pool.clone())
        );
        
        // Create storage usage service that uses database for user information
        // and file repository for storage calculation
        let service = Arc::new(application::services::storage_usage_service::StorageUsageService::new(
            file_repository.clone(),
            user_repository,
        ));
        
        tracing::info!("Storage usage service initialized successfully");
        
        // Add the service to the app state
        app_state = app_state.with_storage_usage_service(service.clone());
        
        Some(service)
    } else {
        tracing::info!("Storage usage service is disabled (requires database connection)");
        None
    };
    
    // Wrap in Arc after all modifications
    let app_state = Arc::new(app_state);

    // Build application router
    let api_routes = create_api_routes(folder_service, file_service, Some(i18n_service), trash_service, search_service, share_service, favorites_service, recent_service);
    let web_routes = create_web_routes();
    
    // Build the app router
    // Import auth handler
    use interfaces::api::handlers::auth_handler::auth_routes;
    
    // Create basic app router
    let mut app = Router::new()
        .nest("/api", api_routes)
        .merge(web_routes)
        .layer(TraceLayer::new_for_http());
    
    // Add auth routes if auth is enabled
    if config.features.enable_auth && auth_services.is_some() {
        // Create auth routes with app state
        let auth_router = auth_routes().with_state(app_state.clone());
        
        // Add auth routes at /api/auth
        app = app.nest("/api/auth", auth_router);
    }

    // Preload common directories to warm the cache
    tracing::info!("Preloading common directories to warm up cache...");
    if let Ok(count) = metadata_cache.preload_directory(&storage_path, true, 1).await {
        tracing::info!("Preloaded {} directory entries into cache", count);
    }
    
    // Start server with clear message
    let addr = SocketAddr::from(([0, 0, 0, 0], 8086));
    tracing::info!("Starting OxiCloud server on http://{}", addr);
    
    // Start the server
    tracing::info!("Authentication system initialized successfully");
    
    // Import the redirect middleware
    use crate::interfaces::middleware::redirect::redirect_middleware;
    
    // Apply the redirect middleware to handle legacy routes
    app = app.layer(axum::middleware::from_fn(redirect_middleware));
    
    // Create a standard TCP listener
    let listener = tokio::net::TcpListener::bind(addr).await?;
    tracing::info!("Server binding to http://{}", addr);
    tracing::info!("Starting server with Axum routes...");
    
    // Axum 0.8 requires the state to match the expected type
    // Extract the state from Arc so we can pass it to the router
    let app_state_inner = Arc::try_unwrap(app_state)
        .unwrap_or_else(|arc| (*arc).clone());
    
    // Add global state to the router
    let app = app.with_state(app_state_inner);
    
    // Use axum's serve function with the router with state
    axum::serve(listener, app).await?;
    
    tracing::info!("Server shutdown completed");
    
    Ok(())
}

